/*
*  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. licenses this file to you under the Apache License,
*  Version 2.0 (the "License"); you may not use this file except
*  in compliance with the License.
*  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.bpel.internal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.bpel.Axis2ConfigurationContextObserverImpl;
import org.wso2.carbon.bpel.ode.integration.BPELServer;
import org.wso2.carbon.bpel.ode.integration.BPELServerImpl;
import org.wso2.carbon.datasource.DataSourceInformationRepositoryService;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.utils.Axis2ConfigurationContextObserver;
import org.wso2.carbon.utils.ConfigurationContextService;
import org.wso2.carbon.utils.Utils;
import org.wso2.carbon.application.deployer.service.ApplicationManagerService;

/**
 * @scr.component name="org.wso2.carbon.bpel.BPELServiceComponent" immediate="true"
 * @scr.reference name="datasource.information.repository.service"
 * interface="org.wso2.carbon.datasource.DataSourceInformationRepositoryService"
 * cardinality="1..1" policy="dynamic"  bind="setDataSourceInformationRepositoryService"
 * unbind="unsetDataSourceInformationRepositoryService"
 * @scr.reference name="registry.service" interface="org.wso2.carbon.registry.core.service.RegistryService"
 * cardinality="1..1" policy="dynamic"  bind="setRegistryService" unbind="unsetRegistryService"
 * @scr.reference name="application.manager"
 * interface="org.wso2.carbon.application.deployer.service.ApplicationManagerService"
 * cardinality="1..1" policy="dynamic" bind="setAppManager" unbind="unsetAppManager"
 * @scr.reference name="config.context.service" interface="org.wso2.carbon.utils.ConfigurationContextService"
 * cardinality="1..1" policy="dynamic"  bind="setConfigurationContextService" unbind="unsetConfigurationContextService"
 */

public class BPELServiceComponent {
    private static Log log = LogFactory.getLog(BPELServiceComponent.class);
    private BundleContext bundleContext;
    private boolean dataSourceInfoRepoProvided = false;

    protected void activate(ComponentContext ctxt) {
        try {
            this.bundleContext = ctxt.getBundleContext();
            if (dataSourceInfoRepoProvided) {
                initializeBPELServer();
                Utils.registerDeployerServices(this.bundleContext);
                registerBpsServerService();
                registerAxis2ConfigurationContextObserver();
            }
        } catch (Throwable t) {
            log.error("Failed to activate the BPELServiceComponent", t);
        }
        if(log.isDebugEnabled()) {
            log.debug("BPEL Deployer bundle is activated.");
        }
    }

    protected void setDataSourceInformationRepositoryService(
            DataSourceInformationRepositoryService repositoryService) {
        if (log.isDebugEnabled()) {
            log.debug("DataSourceInformationRepositoryService bound to the BPEL component");
        }
        this.dataSourceInfoRepoProvided = true;
    }

    protected void unsetDataSourceInformationRepositoryService(
            DataSourceInformationRepositoryService repositoryService) {
        if (log.isDebugEnabled()) {
            log.debug("DataSourceInformationRepositoryService unbound from the BPEL component");
        }
        this.dataSourceInfoRepoProvided = false;
    }

    protected void setAppManager(ApplicationManagerService appService) {
        if (log.isDebugEnabled()) {
            log.debug("CarbonApplicationService bound to the BPEL component");
        }
        BPELServerHolder.getInstance().setApplicationManager(appService);
    }

    protected void unsetAppManager(ApplicationManagerService appService) {
        if (log.isDebugEnabled()) {
            log.debug("CarbonApplicationService unbound from the BPEL component");
        }
        BPELServerHolder.getInstance().setApplicationManager(null);
    }

    protected void setRegistryService(RegistryService registrySvc) {
        if (log.isDebugEnabled()) {
            log.debug("RegistryService bound to the BPEL component");
        }
        BPELServerHolder.getInstance().setRegistryService(registrySvc);
    }

    protected void unsetRegistryService(RegistryService registrySvc) {
        if (log.isDebugEnabled()) {
            log.debug("RegistryService unbound from the BPEL component");
        }
        BPELServerHolder.getInstance().setRegistryService(null);        
    }

    protected void setConfigurationContextService(ConfigurationContextService contextService) {
        if (log.isDebugEnabled()) {
            log.debug("ConfigurationContextService bound to the BPEL component");
        }
        BPELServerHolder.getInstance().setCcServiceInstance(contextService);
    }

    protected void unsetConfigurationContextService(ConfigurationContextService contextService) {
        if (log.isDebugEnabled()) {
            log.debug("ConfigurationContextService unbound from the BPEL component");
        }
        BPELServerHolder.getInstance().setCcServiceInstance(null);
    }

    public static RegistryService getRegistryService(){
        return BPELServerHolder.getInstance().getRegistryService();
    }

    public static ApplicationManagerService getAppManager() {
        if (BPELServerHolder.getInstance().getApplicationManager() == null) {
            String msg = "Before activating BPEL bundle, an instance of "
                            + "CarbonApplicationService should be in existence";
            log.error(msg);
        }
        return BPELServerHolder.getInstance().getApplicationManager();
    }

    public static BPELServer getBPELServer(){
        return BPELServerHolder.getInstance().getBpelServer();
    }

    private void registerAxis2ConfigurationContextObserver(){
        this.bundleContext.registerService(Axis2ConfigurationContextObserver.class.getName(),
                                           new Axis2ConfigurationContextObserverImpl(),
                                           null);
    }

    private static void initializeBPELServer() throws Exception {
        BPELServerHolder.getInstance().setBpelServer(BPELServerImpl.getInstance());
        BPELServerHolder.getInstance().getBpelServer().setSupperTenantConfigurationContext(
                BPELServerHolder.getInstance().getCcServiceInstance().getServerConfigContext());
        log.info("Initializing BPEL Engine........");
        BPELServerHolder.getInstance().getBpelServer().init();

        // To handle JVM shutdowns
        Runtime.getRuntime().addShutdownHook(new BPELServerShutDown(BPELServerHolder.getInstance().
                getBpelServer()));
    }
    
    private void registerBpsServerService() {
        this.bundleContext.registerService(BPELServer.class.getName(),
                                           BPELServerHolder.getInstance().getBpelServer(), null);
    }

    private static class BPELServerShutDown extends Thread {
        private BPELServerImpl bpsServer;

        private BPELServerShutDown(BPELServerImpl bpsServer) {
            super();
            this.bpsServer = bpsServer;
        }

        @Override
        public void run() {
            log.info("Shutting down BPEL Server........");
            try {
                bpsServer.shutdown();
            } catch (Exception e) {
                log.error("Error when shutting down BPEL Server.", e);
            }
        }
    }

}
